Skip to content

Conversation

@dprevost-LMI
Copy link
Contributor

@dprevost-LMI dprevost-LMI commented Dec 30, 2025

Fixes #1982.
Now:

  • When not using .not, the result returned by waitUntil is still true for success and false for failure
  • When using .not, the result returned by waitUntil is now always false for success and true for failure since Jest's expect framework inverts the boolean later on.
  • No need to pass isNot anymore since we do not want to rely on it to fail fast, instead we wait for the condition to be true (or timeout) and test the same really has without isNot
  • When we have an error, we simply rethrow it
  • Added wdio matcher integration tests to ensure .not behaviour is conserved over time
  • Added a test for the below example representing the initial bug targeted to be fixed

⚠️ Possible impact: if tests are running longer when using .not, this can be mitigated by passing a wait value in the option parameter

Bonus: Fix toHaveElementProperty typing in the d.ts file

Why do we need to wait?
Example: If we have a wait of 10 sec and the text becomes 'GOOD' at 5 sec
Then

expect($('myElement')).toHaveText('GOOD') 

will pass after waiting 5 sec

Also, with today's bug, if you do

expect(element).not.toHaveText('GOOD')

It will also pass because, on the first attempt, it is effectively false.

Having both above conditions pass for the same scenario does not make sense.
By waiting, we ensure we have the 'real' fetched value and negate that 'reality.'

Code representing the above example

  const el = await $('selector')
            vi.mocked(el.isDisplayed)
                .mockResolvedValueOnce(false)
                .mockResolvedValueOnce(false)
                .mockResolvedValueOnce(true)

            // Passes when element becomes displayed
            await expectLib(el).toBeDisplayed({ wait: 300, interval: 100 })

            vi.mocked(el.isDisplayed)
                .mockResolvedValueOnce(false)
                .mockResolvedValueOnce(false)
                .mockResolvedValueOnce(true)

            // Should not pass with the same scenario to be consistent
            await expect(() => expectLib(el).not.toBeDisplayed({ wait: 300, interval: 100 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be displayed
Expected [not]: "not displayed"
Received      : "displayed"`)
        })

@dprevost-LMI dprevost-LMI marked this pull request as ready for review December 30, 2025 06:08
@dprevost-LMI
Copy link
Contributor Author

dprevost-LMI commented Dec 30, 2025

We run the condition function until the timeout, so it can become true before checking for the negation of it

Might need a second opinion here, since now when using expect().not, the test will be slower since we need to "always" timeout

@christian-bromann
Copy link
Member

@dprevost-LMI merged some PRs, mind updating this branch?

@dprevost-LMI dprevost-LMI force-pushed the fix-isNot-not-always-considered-in-waitUntil branch from 3c7baa4 to da0b63e Compare January 4, 2026 22:19
@dprevost-LMI
Copy link
Contributor Author

@christian-bromann Done
Let me know if you have a second opinion on the small concern raised (See here)

@christian-bromann
Copy link
Member

Let's rebase, happy to merge after.

@dprevost-LMI
Copy link
Contributor Author

@christian-bromann ready again

@dprevost-LMI
Copy link
Contributor Author

🤔 When using .not, the pass in the assertion result must be false and not true to properly throw an error...
Revisting the fix


})

describe('Matchers pass when using `.not`', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add integration of .not with Jest's expect lib to ensure we process them correctly


})

describe('Matcher eventually passing', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test around the fix I made to ensure consistent behaviour between a matcher and its negated case when we wait for a given result.

await expect(() => expectLib(el).not.toBeDisplayed({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be displayed
Expected [not]: "not displayed"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failure message fixed in #1987

@dprevost-LMI dprevost-LMI force-pushed the fix-isNot-not-always-considered-in-waitUntil branch 5 times, most recently from a11d10f to e68c889 Compare January 16, 2026 12:50
fix UT following isNot fixes in waitUntil
chore: ensure using `expect(result.message()).toContain('not')`
chore: include `toHaveTitle` test on main + increase coverage %

Add toHaveTitle on main so it will be easier to "compare" with multi-remote  support changes
Squash commits

fix develop merge quirks
fix incorrect test and title

Remove any and fix mocks

When using `.not` result.pass must be false for the test to pass

it is the layer of Jest that inverted the pass pass =false to true when using `.not`

Bring back isNot pass=false for success and isNot pass=true for failures

Add integrated test to ensure isNot behavior + matcher consistency

- Add test on top of Jest's expect lib to ensure that that layer works with our matcher and `.not` correctly process.
- Add test to cover the previous inconsistency of similarly case passing with and without `.not`

Make test a bit faster

Review test for null/undefined cases in toHaveElementPropert
@dprevost-LMI dprevost-LMI force-pushed the fix-isNot-not-always-considered-in-waitUntil branch from 9bed9e3 to 5811396 Compare January 16, 2026 13:07
@dprevost-LMI dprevost-LMI marked this pull request as ready for review January 16, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Negation isNot is not always properly considered in waitUntil

2 participants